/*
	the ball

	notes: collision / collide is no good.
		bounce is good.
*/
#include <hge.h>
#include <hgesprite.h>
#include <hgevector.h>
#include "ball.h"
#include "obstacle.h"


enum Status {CAUGHT=0, FLYING, DEAD};
hgeVector centerToCorner;
hgeVector ballProjected;
hgeVector blockProjected;
hgeVector temp;
float dp;

HEFFECT wsnd;

Ball::Ball()
{
	state = CAUGHT;
	dx=dy=0.0f;
	x=32.0f; y=200.0f;
	/*w=h=32.0f;*/
	speed=90.0f;
	drag=0.85f;
	rotation=0.0f;
	rotationIncrement=3.5f;
	direction.x=1.0f;
	direction.y=0.0f;
	travel.x=0.0f;
	travel.y=0.0f;
	won=false;
	
	box=new hgeRect();
	tex=hge->Texture_Load("resources/images/ball.png");
	//wsnd=hge->Effect_Load("resources/sounds/ballcollide.wav");
	spr=new hgeSprite(tex,0,0,32,32);
	spr->SetBlendMode(BLEND_COLORMUL | BLEND_ALPHABLEND | BLEND_NOZWRITE);
	spr->SetColor(0xFF44FF66);
	spr->SetHotSpot(16,16);
}

Ball::~Ball()
{
	hge->Texture_Free(tex);
	delete spr;
	delete box;
}

bool Ball::IsCaught()
{
	return (state==CAUGHT);
}

bool Ball::Dying()
{
	switch(state){
	case CAUGHT: return false;
	case FLYING: //die if it's going too slow or OOB
		if (travel.Length()<2.75f) return true;
		if (y>600||y<0||x>800)	return true;
		
		return false;
	case DEAD:
		break;
	}
	
	return false;
}

void Ball::Die()
{
	state = DEAD; //could maybe do some cool dead movement back to position
	CatchMe();
}

bool Ball::Won()
{
	bool twon=won; //temp won
	won=false; //reset won state.
	return twon;

}

void Ball::Movement()
{
	switch(state){
	case CAUGHT:
	case FLYING: 
		x+=travel.x; y+=travel.y;
		travel*=drag;
		if (x<24){ //only thing collision was really doing any more
			CatchMe();
		}
		//if (Collision()) Collide(); //garbage.
		break;
	case DEAD:
		break;
	}
}

void Ball::Collide()//wut's up I'm not used either
{	
	switch(state){
	case CAUGHT:
		travel.y*=-0.5f;
		break;
	case FLYING:
	case DEAD:
		break;
	}
}

void Ball::Rotate(float dt, int whichWay)
{
	if (((1.5>rotation)&&(whichWay==1))|((rotation>-1.5)&&(whichWay==-1))){
		rotation+=dt*rotationIncrement*whichWay;
		direction.Rotate(dt*rotationIncrement*whichWay);
	}
}

void Ball::Move(float dt, int whichWay)
{	
	if ((584>y)&&(y>16)) travel.y+=speed*dt*whichWay;
	else
		travel.y*=-1;
}

void Ball::Shoot()
{
	state=FLYING;
	drag=0.995f;
	travel=direction*speed*0.2f;
}

//void Ball::Bounce(int dir)//needs improvement
int Ball::Bounce(Obstacle *obstacle)
{
	//voronoi regions of the four basic sides of a square
	if (obstacle->winner) won=true;
	if( x<obstacle->x && y>obstacle->y && y<obstacle->y+obstacle->h)//west
		if((x+16>obstacle->x)/*||(x+16+travel.x>obstacle->x)*/){//penetration or soon
			x-=x+16-obstacle->x;
			travel.x*=-1;
			return 1;
		}
	if( x>obstacle->x+obstacle->w && y>obstacle->y && y<obstacle->y+obstacle->h)//east
		if((x-16<obstacle->x+obstacle->w)/*||(x-16+travel.x<obstacle->x+obstacle->w)*/){//penetration or by the next frame
			x=obstacle->x+obstacle->w+16;
			travel.x*=-1;
			return 1;
		}
	if( x>obstacle->x && x<obstacle->x+obstacle->w && y<obstacle->y)//north
		if(y+16>obstacle->y){
			y=obstacle->y-16;
			travel.y*=-1;
			return 1;
		}
	if( x>obstacle->x && x<obstacle->x+obstacle->w && y>obstacle->y+obstacle->h)//south
		if(y-16<obstacle->y+obstacle->h){//penetration or by the next frame
			y=obstacle->y+obstacle->h+16;
			travel.y*=-1;
			return 1;
		}
	//voronoi regions around the corners
	if (x<obstacle->x && y<obstacle->y){ //NW
		centerToCorner.x=obstacle->x-x;
		centerToCorner.y=obstacle->y-y;
		if(centerToCorner.Length()<16){
			//centerToCorner.x;
			//centerToCorner.y;
			x-=17-centerToCorner.x;//this is hacky just to get the ball out of the box area
			y-=17-centerToCorner.y;
			temp.x=-1; //temp is the axis vectors.  really this just bounces it out...
			temp.y=-1;
			centerToCorner.Normalize();
			dp=travel%temp;//dot product
			travel.x=centerToCorner.x+temp.x*dp+travel.x-temp.x*dp;
			travel.y=centerToCorner.y+temp.y*dp+travel.x-temp.y*dp; //travel is projected onto the collision vector.
			return 1;
		}

	}
	if (x<obstacle->x && y>obstacle->y+obstacle->h){ //SW
		centerToCorner.x=obstacle->x-x;
		centerToCorner.y=y-obstacle->y+obstacle->h;
		if(centerToCorner.Length()<16){
			//centerToCorner.x;
			//centerToCorner.y;
			x-=17-centerToCorner.x;
			y+=17-centerToCorner.y;
			temp.x=-1; //temp is the axis vectors.  really this just bounces it out...
			temp.y=-1;
			centerToCorner.Normalize();
			dp=travel%temp;//dot product
			travel.x=centerToCorner.x+temp.x*dp+travel.x-temp.x*dp;
			travel.y=centerToCorner.y+temp.y*dp+travel.x-temp.y*dp; //travel is projected onto the collision vector.
			return 1;
		}
	}
	if (x>obstacle->x+obstacle->w && y<obstacle->y){ //NE
		centerToCorner.x=x-obstacle->x+obstacle->w;
		centerToCorner.y=obstacle->y-y;
		if(centerToCorner.Length()<16){
			//centerToCorner.x;
			//centerToCorner.y;
			x+=17-centerToCorner.x;
			y-=17-centerToCorner.y;
			temp.x=-1; //temp is the axis vectors.  really this just bounces it out...
			temp.y=-1;
			centerToCorner.Normalize();
			dp=travel%temp;//dot product
			travel.x=centerToCorner.x+temp.x*dp+travel.x-temp.x*dp;
			travel.y=centerToCorner.y+temp.y*dp+travel.x-temp.y*dp; //travel is projected onto the collision vector.
			return 1;
		}
	}
	if (x>obstacle->x+obstacle->w && y>obstacle->y+obstacle->h){ //SE
		centerToCorner.x=x-obstacle->w+obstacle->x;
		centerToCorner.y=y-obstacle->h+obstacle->y;
		if(centerToCorner.Length()<16){
			//centerToCorner.x;
			//centerToCorner.y;
			x+=17-centerToCorner.x;
			y+=17-centerToCorner.y;
			temp.x=-1; //temp is the axis vectors.  really this just bounces it out...
			temp.y=-1;
			centerToCorner.Normalize();
			dp=travel%temp;//dot product
			travel.x=centerToCorner.x+temp.x*dp+travel.x-temp.x*dp;
			travel.y=centerToCorner.y+temp.y*dp+travel.x-temp.y*dp; //travel is projected onto the collision vector.
			return 1;
		}
	}
	return 0;
	/*switch(dir){//not so good.
	case 0:
		x-=16;
		travel.x*=-1;
		break;
	case 1:
		y-=16;
		travel.y*=-1;
		break;
	case 2:
		x+=16;
		travel.x*=-1;
		break;
	case 3:
		y+=16;
		travel.y*=-1;
		break;
	}*/
}

bool Ball::Collision()//HAY i'm NOT USED
{	
	switch(state){
	case CAUGHT:
		if (y>584) return true;
		if (y<16) return true;
	case FLYING:
		if (y>584){
			hge->Effect_Play(wsnd);
			travel.y*=-1;
			y-=16;
		}
		if (y<16){
			hge->Effect_Play(wsnd);
			travel.y*=-1;
			y+=16;
		}
		if (x<24){
			CatchMe();
		}
		if (x>784){
			hge->Effect_Play(wsnd);
			travel.x*=-1;
			x-=16;
		}
		//return true;
	case DEAD:
		break;
	}	

	return false;
}

hgeRect* Ball::Box()//not acutally used
{
	//hgeRect *ballBox=new hgeRect();
	box->SetRadius(x,y,16);
	return box;
}

void Ball::Render()
{
	spr->RenderEx(x,y,rotation);
}

void Ball::Render(float x, float y)
{
	spr->Render(x,y);
}

/** PRIVATES
*/
void Ball::Win()
{
	won=true;
}

void Ball::CatchMe()
{
	travel.x=0;
	travel.y=0;
	x=32;
	if (state==DEAD) y=300;
	drag=0.85f;
	state=CAUGHT;
}